• 検索結果がありません。

MSG_PEEK|MSG_DONTWAIT);

ドキュメント内 ネットワークプログラミング (ページ 34-71)

データはbufにコピーされる

• ioctl(sockfd, FIONREAD , &nbytes);

使えるOSは限られる(Linuxでは使える)

35

write()

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

unsigned char buf[4];

ssize_t n;

buf[0] = 0x5a;

buf[1] = 0x5b;

buf[2] = 0x5c;

buf[3] = 0x5b;

if (write(sockfd, buf, 4) == -1) { perror("write error");

exit(1);

}

ソケットセンドバッファに余裕がないときにはブ ロックする(エラーにはならない)。

ブロックしないようにするにはノンブロックキグ ソケットオプションを使う(ノンブロッキングにす るとエラー処理とかでだいぶ行数が増える)。

2013-08-27 DAQ-Middlewareトレーニングコース

socket send/receive buffer の大きさ

application

TCP

IP

datalink

application buffer write()

socket send buffer

user process kernel

socket receive buffer

application buffer

read()

socket send/receive buffer の大きさの調整

• 受信に関しては Linux では自動調節機能がある

• 多重読み出しを行うときにはあらかじめ大きくしてお かないと性能がでないことが多い

2013-08-27 DAQ-Middlewareトレーニングコース 37

echo 0 > /proc/sys/net/ipv4/tcp_timestamps

echo 1 > /proc/sys/net/ipv4/tcp_moderate_rcvbuf echo 4194304 > /proc/sys/net/core/wmem_max

echo 4194304 > /proc/sys/net/core/rmem_max

echo 4194304 > /proc/sys/net/core/wmem_default echo 4194304 > /proc/sys/net/core/rmem_default

echo 4096 131072 4194304 > /proc/sys/net/ipv4/tcp_rmem echo 4096 131072 4194304 > /proc/sys/net/ipv4/tcp_wmem

# 131072 128kB

がデフォルト値。もっと大きくしておかないとだめな場合もある

#

あるいはソケット個別に大きくすることもできる(

setsockopt())

ソケットレシーブバッファの大きさ調節による改善例

多重読み出しで複数モジュールから読み出し

各モジュールは同一レートでデータを送ってくるようにセット 読むモジュール数を

1, 2, 3,

と増加させていった。

調節前 調節後

ここまでのまとめ

• ソケットファイルディスクリプタを取得するとあ とは通常のファイルの読み書きと同様

• ファイルを読むときとは違って指定したサイズ が必ずしも読めるとは限らない。指定したサ イズ必ず読みたければそのような関数を作る 必要がある。

2013-08-27 DAQ-Middlewareトレーニングコース 39

ネットワークバイトオーダー (1)

• unsigned char buf[10];

アドレスは buf[0], buf[1], buf[2] の順に大きくなる

• unsigned char buf[10];

write(sockfd, buf, 10) ;

とすると buf[0], buf[1], buf[2] … の順に送られる。

• read(sockfd, buf, 10);

きた順に buf[0], buf[1], buf[2] に格納される。

41

ネットワークバイトオーダー (2)

// int

がどういう順番でメモリーに

// 入っているか調べるプログラム

#include <stdio.h>

int main(int argc, char *argv[]) {

int i;

union num_tag {

unsigned char c[sizeof(int)];

unsigned int num;

} u_num;

u_num.num = 0x01020304;

for (i = 0; i < sizeof(int); i++) {

printf("u_num.c[%d]: %p 0x%02x ¥n", i, &u_num.c[i], u_num.c[i]);

}

return 0;

}

出力

(i386)

u_num.c[0]: 0xbfbfe850 0x04 u_num.c[1]: 0xbfbfe851 0x03 u_num.c[2]: 0xbfbfe852 0x02 u_num.c[3]: 0xbfbfe853 0x01

2013-08-27 DAQ-Middlewareトレーニングコース

ネットワークバイトオーダー (3)

big endian では 0x 01020304 = 16909060 little endian では 0x 04030201 = 67305985 ネットワークバイトオーダーは big endian

0x 01 02 03 04

の順に送られてきたデータを

read(sockfd, buf, 4)

で読んだ場合

0x01 0x02 0x03 0x04 0x01 0x02 0x03 0x04

big endian little endian

buf buf

43

ネットワークバイトオーダー (4)

• ホストオーダー⇔ネットワークバイトオーダー 変換関数

– htonl (host to network long) – htons (host to network short) – ntohl (network to host long) – ntohs (network to host short)

2013-08-27 DAQ-Middlewareトレーニングコース

daytime client (1)

• xinetd 内蔵サーバー daytime (port 13)

• /etc/xinetd.d/daytime-stream にて disable = no

に変更して service xinetd restart

• telnet localhost 13

すると現在日時が表示される

2013-08-27 DAQ-Middlewareトレーニングコース 45

#include <sys/socket.h>

#include <sys/types.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#define MAXLINE 1024

int main(int argc, char *argv[]) {

unsigned char line[MAXLINE + 1];

struct sockaddr_in servaddr;

char *ip_address = "127.0.0.1";

int port = 13;

int sockfd, n;

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(port);

n = inet_pton(AF_INET, ip_address, &servaddr.sin_addr);

if (n < 0) {

perror("inet_pton");

exit(1);

}

else if (n == 0) {

fprintf(stderr, "invalid address %s", ip_address);

exit(1);

}

if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket");

exit(1);

}

if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connect");

exit(1);

}

2013-08-27 DAQ-Middlewareトレーニングコース 47

for ( ; ; ) {

n = read(sockfd, line, MAXLINE);

if (n < 0) {

perror("read");

exit(1);

}

else if (n == 0) { printf("EOF¥n");

break;

}

line[n] = '¥0'; /* string termination */

printf("%s¥n", line);

}

if (close(sockfd) < 0) { perror("close");

exit(1);

}

return 0;

}

0123456789012345678901234 5 6 07 AUG 2012 13:02:10 JST¥r¥n¥0

[daq@localhost daytimeclient]$ ./daytimeclient | hexdump -vC

00000000 30 37 20 41 55 47 20 32 30 31 32 20 31 33 3a 30 |07 AUG 2012 13:0|

00000010 32 3a 31 30 20 4a 53 54 0d 0a 0a 45 4f 46 0a |2:10 JST...EOF.|

情報のありか

• Manual Page

• 本

49

Manual Pages

• セクション

– 1 (Utility Program) – 2 (System call)

– 3 (Library) – 4 (Device)

– 5 (File format) – 6 (Game)

– 7 (Misc.)

– 8 (Administration)

Linux だとこの他 – 3P (Posix)

2013-08-27 DAQ-Middlewareトレーニングコース

Manual Pages

• man コマンド

• Linux のマニュアルページは

– http://www.kernel.org/doc/man-pages/

– 最新のマニュアルはここで読める。

– 利用している kernel 、 library 等のバージョンに注

意する必要がある。

51

Manual Pages

• Header

READ(3P) POSIX Programmer's Manual READ(3P) READ(2) Linux Programmer's Manual READ(2)

• SYNOPSIS

• DESCRIPTION

• RETURN VALUE

• SEE ALSO

• EXAMPLE

2013-08-27 DAQ-Middlewareトレーニングコース

Manual Pages( 例題 )

READ(2) Linux Programmer's Manual READ(2) NAME

read - read from a file descriptor SYNOPSIS

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION

read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.

RETURN VALUE

ERRORS

CONFORMING TO

SVr4, 4.3BSD, POSIX.1-2001.

NOTES

53

Manual Pages( 例題 )

READ(2) Linux Programmer's Manual READ(2) NAME

read - read from a file descriptor SYNOPSIS

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION

read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.

RETURN VALUE

ERRORS

CONFORMING TO

SVr4, 4.3BSD, POSIX.1-2001.

NOTES

SEE ALSO

2013-08-27 DAQ-Middlewareトレーニングコース

Utility

• gettimeofday()

• nc

• tcpdump 、 wireshark (ex. ethereal)

55

gettimeofday() で現在時刻の取得

struct timeval start, end, diff;

if (gettimeofday(&start, NULL) < 0) { err(1, "gettimeofday");

}

/* ... */

if (getimeofday(&end, NULL) < 0) { err(1, "gettimeofday");

}

/*

時間差をとるには引き算してもよいし、

timersub()

関数を使ってもよい

timersub(&end, &start, &diff);

printf("%ld.%06ld¥n", result.tv_sec, result.tv_usec);

#include <sys/time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);

Linux

では

gettimeofday()

1,000,000

回繰り返して1秒以下(

CPU

に依存する)

2013-08-27 DAQ-Middlewareトレーニングコース

struct timeval {

time_t tv_sec; /* seconds */

suseconds_t tv_usec; /* microseconds */

};

ナノ秒まで必要なとき

clock_gettime(CLOCK_REALTIME, &ts);

コンパイル時に

-lrt

が必要

struct timespec {

time_t tv_sec; /* seconds */

long tv_nsec; /* nanoseconds */

};

余談: 最近のファイルシステムのタイムスタンプはナノ秒まで記録されている

% touch X

% ls -l --full X

-rw-rw-r-- 1 sendai sendai 0 2012-08-02 15:02:55.362116699 +0900 X

nc (netcat)

• nc - arbitrary TCP and UDP connections and listens

• nc 192.168.0.16 > datafile で接続してデータを とってみる

• nc 192.168.0.16 | tee log.dat | prog_histo

2013-08-27 DAQ-Middlewareトレーニングコース 57

% nc -l 1234

(

これで待機して別の端末から

) Hello, world

% nc 127.0.0.1 1234 Hello, world

tcpdump

• ネットワーク上を流れているパケットを見るコマンド – 接続できないんだけどパケットはでているのか?

– データが読めないんだけど向こうからパケットは きているんでしょうか?

• root にならないと使えない

• 起動方法

# tcpdump -n -w dumpfile -i eth0 # tcpdump -n -r dumpfile

• Selector

# tcpdump -n -r host 192.168.0.16

# tcpdump -n -r src 192.168.0.16 and dst 192.168.0.17

59

tcpdump 出力例

TCP の 3way ハンドシェイク付近:

11:27:55.137827 IP 192.168.0.16.59448 > 192.168.0.17.http: S 153443204:

153443204(0) win 5840 <mss 1460,sackOK,timestamp 587094474 0,nop,wscale 7>

11:27:55.139573 IP 192.168.0.17.http > 192.168.0.16.59448: S 4091282933:

4091282933(0) ack 153443205 win 65535 <mss 1460,nop,wscale 1,nop,nop,timestamp 3029380287 587094474,sackOK,eol>

11:27:55.139591 IP 192.168.0.16.59448 > 192.168.0.17.http: . ack 1 win 46

<nop,nop,timestamp 587094479 3029380287>

11:27:55.139751 IP 192.168.0.16.59448 > 192.168.0.17.http: P 1:103(102) ack 1 win 46 <nop,nop,timestamp 587094479 3029380287>

11:27:55.143520 IP 192.168.0.17.http > 192.168.0.16.59448: P 1:252(251) ack103 win 33304 <nop,nop,timestamp 3029380290 587094479>

2013-08-27 DAQ-Middlewareトレーニングコース

tcpdump - 時刻情報

• 絶対時刻ではなくて相対的な時間に変換する プログラムを作っておくと便利なことがある。

0.000000 0.000000 IP 192.168.0.16.59448 > 192.168.0.17.http: S 153443204:1534432 0.001746 0.001746 IP 192.168.0.17.http > 192.168.0.16.59448: S 4091282933:409128 0.001764 0.000018 IP 192.168.0.16.59448 > 192.168.0.17.http: . ack 1 win 46 <nop 0.001924 0.000160 IP 192.168.0.16.59448 > 192.168.0.17.http: P 1:103(102) ack 1 0.005693 0.003769 IP 192.168.0.17.http > 192.168.0.16.59448: P 1:252(251) ack 10 0.005703 0.000010 IP 192.168.0.16.59448 > 192.168.0.17.http: . ack 252 win 54 <n 1.107822 1.102119 IP 192.168.0.16.59448 > 192.168.0.17.http: F 103:103(0) ack 25 1.108482 0.000660 IP 192.168.0.17.http > 192.168.0.16.59448: . ack 104 win 33304 1.109608 0.001126 IP 192.168.0.17.http > 192.168.0.16.59448: F 252:252(0) ack 10 1.109618 0.000010 IP 192.168.0.16.59448 > 192.168.0.17.http: . ack 253 win 54 <n

最初の欄は

SYN

を送ってからの経過時間

2番目の欄は直前の行との時間差を示すもの

61

tcpdump + program log

• tcpdump の時刻情報と同じ時刻フォーマットでロ

グを出すようにしておいて tcpdump をとりつつプ ログラムを走らせあとからマージする:

(tcpdump -n -r tcpdump.out; cat log) | sort -n

2013-08-27 DAQ-Middlewareトレーニングコース

NEUNET Protocol

クライアント サーバー(検出器モジュール)

length request

length + data

length request

length + data

63

tcpdump + program log

0.000000 0.000000 connect start

0.000063 0.000063 IP 192.168.0.204.57447 > 192.168.0.20.telnet: S 4076228960:407 0.000128 0.000065 IP 192.168.0.20.telnet > 192.168.0.204.57447: S 3718362368:371 0.000159 0.000031 IP 192.168.0.204.57447 > 192.168.0.20.telnet: . ack 1 win 5840 0.000215 0.000056 write length

0.000227 0.000012 IP 192.168.0.204.57447 > 192.168.0.20.telnet: P 1:9(8) ack 1 w 0.000234 0.000007 read length + data

0.000275 0.000041 IP 192.168.0.20.telnet > 192.168.0.204.57447: . ack 9 win 6551 0.002269 0.001994 IP 192.168.0.20.telnet > 192.168.0.204.57447: . 1:5(4) ack 9 w 0.002284 0.000015 IP 192.168.0.204.57447 > 192.168.0.20.telnet: . ack 5 win 5840 0.002300 0.000016 write length

0.002306 0.000006 IP 192.168.0.204.57447 > 192.168.0.20.telnet: P 9:17(8) ack 5 0.002312 0.000006 read length + data

0.002369 0.000057 IP 192.168.0.20.telnet > 192.168.0.204.57447: . ack 17 win 655 0.002568 0.000199 IP 192.168.0.20.telnet > 192.168.0.204.57447: . 5:1465(1460) a 0.002583 0.000015 IP 192.168.0.204.57447 > 192.168.0.20.telnet: . ack 1465 win 8 0.002717 0.000134 IP 192.168.0.20.telnet > 192.168.0.204.57447: . 1465:2925(1460

2013-08-27 DAQ-Middlewareトレーニングコース

wireshark

• yum install wireshark-gnome (GUI つきのをイ ンストールする)

• Ethernet 、 IP, TCP のヘッダがどこか色つきで

表示してくれるので便利

2013-08-27 DAQ-Middlewareトレーニングコース 65

MACアドレスか

らベンダーを調 べて表示する

(らしい)

wireshark

• 複数の TCP セッションが あっても

Analyze→Follow TCP

Stream で追跡可能

wireshark

2013-08-27 DAQ-Middlewareトレーニングコース 67

wireshark

• データのダンプもできる

wireshark

• フローグラフ

2013-08-27 DAQ-Middlewareトレーニングコース 69

tcpflow

• tcpdump 、 wireshark 等でキャプチャしたファイ ルからデータフローを取り出すことができる

• 同様なソフトウェアは他にもある

ドキュメント内 ネットワークプログラミング (ページ 34-71)

関連したドキュメント